/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
 */
package td.client.view;

import java.util.Comparator;
import java.util.Date;

import td.client.place.NameTokens;
import td.client.presenter.handlers.ThoughtListingUiHandlers;
import td.domain.Thinker;
import td.domain.Thought;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.ProvidesKey;
import com.google.inject.Inject;

/**
 * @author Artem Shamsutdinov
 * 
 */
public class ThoughtListingView extends AbstractViewWithUiHandlers<ThoughtListingUiHandlers>
		implements ThoughtListingUiHandlers.MyView {

	public interface Binder extends UiBinder<Widget, ThoughtListingView> {
	}

	/**
	 * The main DataGrid.
	 */
	@UiField(provided = true)
	CellTable<Thought> cellTable;

	/**
	 * The pager used to change the range of data.
	 */
	@UiField(provided = true)
	SimplePager pager;

	@UiField
	Label listingTitle;

	@UiField
	RadioButton topRead;
	@UiField
	RadioButton topTaggings;
	@UiField
	RadioButton topReferenced;

	enum ListingType {
		TOP_READ, TOP_TAGGINGS, TOP_REFERENCED
	};

	private ListingType listingType = null;

	DateTimeFormat dateFormat = DateTimeFormat
			.getFormat(DateTimeFormat.PredefinedFormat.DATE_SHORT);

	ListHandler<Thought> sortHandler;

	Column<Thought, Hyperlink> titleColumn = new Column<Thought, Hyperlink>(
			new AbstractCell<Hyperlink>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Hyperlink value, SafeHtmlBuilder sb) {
					sb.append(SafeHtmlUtils.fromTrustedString(value.toString()));
				}
			}) {
		@Override
		public Hyperlink getValue(Thought thought) {
			String text = thought.getTitle();
			String targetHistoryToken = NameTokens.detail + ";name="
					+ thought.getId();
			return new Hyperlink(text, targetHistoryToken);
		}
	};

	Column<Thought, Hyperlink> thinkerColumn = new Column<Thought, Hyperlink>(
			new AbstractCell<Hyperlink>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Hyperlink value, SafeHtmlBuilder sb) {
					sb.append(SafeHtmlUtils.fromTrustedString(value.toString()));
				}
			}) {
		@Override
		public Hyperlink getValue(Thought thought) {
			Thinker thinker = thought.getThinker();
			String text = thinker.getThinkerId();
			String targetHistoryToken = NameTokens.thinker + ";name="
					+ thinker.getId();
			return new Hyperlink(text, targetHistoryToken);
		}
	};

	Column<Thought, Date> publishedDateColumn = new Column<Thought, Date>(
			new AbstractCell<Date>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Date value, SafeHtmlBuilder sb) {
					sb.appendEscaped(dateFormat.format(value));
				}
			}) {
		@Override
		public Date getValue(Thought thought) {
			return thought.getPublishedDate();
		}
	};

	Column<Thought, Long> numReadsColumn = new Column<Thought, Long>(
			new AbstractCell<Long>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Long value, SafeHtmlBuilder sb) {
					sb.appendEscaped(value.toString());
				}
			}) {
		@Override
		public Long getValue(Thought thought) {
			return thought.getNumReads();
		}
	};

	Column<Thought, Long> numTaggingsColumn = new Column<Thought, Long>(
			new AbstractCell<Long>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Long value, SafeHtmlBuilder sb) {
					sb.appendEscaped(value.toString());
				}
			}) {
		@Override
		public Long getValue(Thought thought) {
			return thought.getNumTaggings();
		}
	};

	Column<Thought, Long> numReferencedColumn = new Column<Thought, Long>(
			new AbstractCell<Long>() {

				@Override
				public void render(
						com.google.gwt.cell.client.Cell.Context context,
						Long value, SafeHtmlBuilder sb) {
					sb.appendEscaped(value.toString());
				}
			}) {
		@Override
		public Long getValue(Thought thought) {
			return (thought.getReferencingThoughts() != null) ? (long) thought
					.getReferencingThoughts().size() : 0L;
		}
	};

	public static final ProvidesKey<Thought> KEY_PROVIDER = new ProvidesKey<Thought>() {
		@Override
		public Object getKey(Thought item) {
			return item == null ? null : item.getId();
		}
	};

	private ListDataProvider<Thought> dataProvider = new ListDataProvider<Thought>();

	@Inject
	public ThoughtListingView(final Binder binder) {

		cellTable = new CellTable<Thought>(KEY_PROVIDER);
		cellTable.setWidth("100%", true);

		sortHandler = new ListHandler<Thought>(dataProvider.getList());
		cellTable.addColumnSortHandler(sortHandler);

		pager = new SimplePager(TextLocation.CENTER);
		pager.setDisplay(cellTable);
		dataProvider.addDataDisplay(cellTable);

		initTableColumns(cellTable, sortHandler);

		widget = binder.createAndBindUi(this);
		topRead.setValue(true);
	}

	/**
	 * Add the columns to the table.
	 */
	private void initTableColumns(CellTable<Thought> cellTable,
			ListHandler<Thought> sortHandler) {

		titleColumn.setSortable(true);
		sortHandler.setComparator(titleColumn, new Comparator<Thought>() {
			@Override
			public int compare(Thought o1, Thought o2) {
				return o1.getTitle().compareTo(o2.getTitle());
			}
		});
		cellTable.addColumn(titleColumn, "Title");
		cellTable.setColumnWidth(thinkerColumn, 50, Unit.PCT);

		thinkerColumn.setSortable(true);
		sortHandler.setComparator(thinkerColumn, new Comparator<Thought>() {
			@Override
			public int compare(Thought o1, Thought o2) {
				return o1.getThinker().getThinkerId()
						.compareTo(o2.getThinker().getThinkerId());
			}
		});
		cellTable.addColumn(thinkerColumn, "Thinker");
		cellTable.setColumnWidth(thinkerColumn, 15, Unit.PCT);

		publishedDateColumn.setSortable(true);
		sortHandler.setComparator(publishedDateColumn,
				new Comparator<Thought>() {
					@Override
					public int compare(Thought o1, Thought o2) {
						return o1.getPublishedDate().compareTo(
								o2.getPublishedDate());
					}
				});
		cellTable.addColumn(publishedDateColumn, "Published");
		cellTable.setColumnWidth(publishedDateColumn, 15, Unit.PCT);
		numReadsColumn.setSortable(true);
		sortHandler.setComparator(numReadsColumn, new Comparator<Thought>() {
			@Override
			public int compare(Thought o1, Thought o2) {
				return o1.getNumReads().compareTo(o2.getNumReads());
			}
		});

		numTaggingsColumn.setSortable(true);
		sortHandler.setComparator(numTaggingsColumn, new Comparator<Thought>() {
			@Override
			public int compare(Thought o1, Thought o2) {
				return o1.getNumTaggings().compareTo(o2.getNumTaggings());
			}
		});

		numReferencedColumn.setSortable(true);
		sortHandler.setComparator(numReferencedColumn,
				new Comparator<Thought>() {
					@Override
					public int compare(Thought o1, Thought o2) {
						return Long.valueOf(o1.getReferencingThoughts().size())
								.compareTo(
										(long) o2.getReferencingThoughts()
												.size());
					}
				});

		addNumReadsColumn();
	}

	public void addNumReadsColumn() {
		removeCurrentColumn();
		cellTable.addColumn(numReadsColumn, "# Reads");
		cellTable.setColumnWidth(numReadsColumn, 20, Unit.PCT);
		cellTable.getColumnSortList().clear();
		cellTable.getColumnSortList().push(numReadsColumn);
		this.listingType = ListingType.TOP_READ;
	}

	public void addNumTaggingsColumn() {
		removeCurrentColumn();
		cellTable.addColumn(numTaggingsColumn, "# Taggings");
		cellTable.setColumnWidth(numTaggingsColumn, 20, Unit.PCT);
		cellTable.getColumnSortList().clear();
		cellTable.getColumnSortList().push(numTaggingsColumn);
		this.listingType = ListingType.TOP_TAGGINGS;
	}

	public void addNumReferencedColumn() {
		removeCurrentColumn();
		cellTable.addColumn(numReferencedColumn, "# Referenced");
		cellTable.setColumnWidth(numReferencedColumn, 20, Unit.PCT);
		cellTable.getColumnSortList().clear();
		cellTable.getColumnSortList().push(numReferencedColumn);
		this.listingType = ListingType.TOP_REFERENCED;
	}

	private void removeCurrentColumn() {
		if (listingType == ListingType.TOP_READ) {
			cellTable.removeColumn(numReadsColumn);
		}
		if (listingType == ListingType.TOP_TAGGINGS) {
			cellTable.removeColumn(numTaggingsColumn);
		}
		if (listingType == ListingType.TOP_REFERENCED) {
			cellTable.removeColumn(numReferencedColumn);
		}
	}

	public Label getListingTitle() {
		return listingTitle;
	}

	public CellTable<Thought> getCellTable() {
		return cellTable;
	}

	public SimplePager getPager() {
		return pager;
	}

	public void setCellTable(CellTable<Thought> cellTable) {
		this.cellTable = cellTable;
	}

	public void setPager(SimplePager pager) {
		this.pager = pager;
	}

	public ListDataProvider<Thought> getDataProvider() {
		return dataProvider;
	}

	public void refresh() {
		dataProvider.refresh();
	}

	public RadioButton getTopRead() {
		return topRead;
	}

	public RadioButton getTopTaggings() {
		return topTaggings;
	}

	public RadioButton getTopReferenced() {
		return topReferenced;
	}

}